#ifndef __WIZ_DATATYPE_TUPLE_HPP__SHANHAOBO_19800429__
#define __WIZ_DATATYPE_TUPLE_HPP__SHANHAOBO_19800429__

#include "./WizDataTypeTupleCons.hpp"
#include "./WizDataTypeTupleElement.hpp"
#include "../../Core/Container/WizDataTypePair.hpp"

namespace Wiz
{
    namespace Tuple
    {
        namespace Index
        {
            template <::Wiz::Int::Type N>
            struct Type
            {};

            ::Wiz::Tuple::Index::Type<0> const _0 = ::Wiz::Tuple::Index::Type<0>();
            ::Wiz::Tuple::Index::Type<1> const _1 = ::Wiz::Tuple::Index::Type<1>();
            ::Wiz::Tuple::Index::Type<2> const _2 = ::Wiz::Tuple::Index::Type<2>();
            ::Wiz::Tuple::Index::Type<3> const _3 = ::Wiz::Tuple::Index::Type<3>();
            ::Wiz::Tuple::Index::Type<4> const _4 = ::Wiz::Tuple::Index::Type<4>();
            ::Wiz::Tuple::Index::Type<5> const _5 = ::Wiz::Tuple::Index::Type<5>();
            ::Wiz::Tuple::Index::Type<6> const _6 = ::Wiz::Tuple::Index::Type<6>();
            ::Wiz::Tuple::Index::Type<7> const _7 = ::Wiz::Tuple::Index::Type<7>();
            ::Wiz::Tuple::Index::Type<8> const _8 = ::Wiz::Tuple::Index::Type<8>();
            ::Wiz::Tuple::Index::Type<9> const _9 = ::Wiz::Tuple::Index::Type<9>();
        } /// end of namespace Index


        ///////////////////////////////////////////////////////////////////////
        // templates for finding out the length of the tuple -------------------
        template<class TupleT>
        struct Length
        {
            typedef typename TupleT::tTail tTail;
            
            static const ::Wiz::Int::Type Value = 1 + (::Wiz::Null::IsA<tTail::tHead>::Value ? 0 : ::Wiz::Tuple::Length<tTail>::Value);
        };
        template<>
        struct Length<::Wiz::Null::Type>
        {
            static const ::Wiz::Int::Type Value = 0;
        };
        template<>
        struct Length<::Wiz::Null::Type const>
        {
            static const ::Wiz::Int::Type Value = 0;
        };
        ////////////////////////////////////////////////////////////////////////////

        // Type class
        template<
            typename T0 = ::Wiz::Null::Type,
            typename T1 = ::Wiz::Null::Type,
            typename T2 = ::Wiz::Null::Type,
            typename T3 = ::Wiz::Null::Type,
            typename T4 = ::Wiz::Null::Type,
            typename T5 = ::Wiz::Null::Type,
            typename T6 = ::Wiz::Null::Type,
            typename T7 = ::Wiz::Null::Type,
            typename T8 = ::Wiz::Null::Type,
            typename T9 = ::Wiz::Null::Type
        >
        class Type : public ::Wiz::Tuple::Cons::FromTuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>::tCons0
        {
        private:
            typedef ::Wiz::Tuple::Cons::FromTuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>  tMappedTuple;
            typedef typename tMappedTuple::tCons9                                           tCons9;
            typedef typename tMappedTuple::tCons8                                           tCons8;
            typedef typename tMappedTuple::tCons7                                           tCons7;
            typedef typename tMappedTuple::tCons6                                           tCons6;
            typedef typename tMappedTuple::tCons5                                           tCons5;
            typedef typename tMappedTuple::tCons4                                           tCons4;
            typedef typename tMappedTuple::tCons3                                           tCons3;
            typedef typename tMappedTuple::tCons2                                           tCons2;
            typedef typename tMappedTuple::tCons1                                           tCons1;
            typedef typename tMappedTuple::tCons0                                           tCons0;

            typedef typename ::Wiz::TypeTraits::Get::ReferenceConst<T0>::tType              tT0ConsRef;
            typedef typename ::Wiz::TypeTraits::Get::ReferenceConst<T1>::tType              tT1ConsRef;
            typedef typename ::Wiz::TypeTraits::Get::ReferenceConst<T2>::tType              tT2ConsRef;
            typedef typename ::Wiz::TypeTraits::Get::ReferenceConst<T3>::tType              tT3ConsRef;
            typedef typename ::Wiz::TypeTraits::Get::ReferenceConst<T4>::tType              tT4ConsRef;
            typedef typename ::Wiz::TypeTraits::Get::ReferenceConst<T5>::tType              tT5ConsRef;
            typedef typename ::Wiz::TypeTraits::Get::ReferenceConst<T6>::tType              tT6ConsRef;
            typedef typename ::Wiz::TypeTraits::Get::ReferenceConst<T7>::tType              tT7ConsRef;
            typedef typename ::Wiz::TypeTraits::Get::ReferenceConst<T8>::tType              tT8ConsRef;
            typedef typename ::Wiz::TypeTraits::Get::ReferenceConst<T9>::tType              tT9ConsRef;
        public:
            typedef tCons0                                                                  tSuper;
            typedef Type                                                                    tThis;
            static const ::Wiz::Int::Type v_Length = ::Wiz::Tuple::Length<tThis>::Value;

            Type() : tCons0(T0(), tCons1(T1(), tCons2(T2(), tCons3(T3(), tCons4(T4(), tCons5(T5(),tCons6(T6(),tCons7(T7(),tCons8(T8(),tCons9(T9()))))))))))
            {}

            explicit Type(tT0ConsRef t0)
                : tCons0(t0, tCons1(T1(), tCons2(T2(), tCons3(T3(), tCons4(T4(), tCons5(T5(),tCons6(T6(),tCons7(T7(),tCons8(T8(),tCons9(T9()))))))))))
            {}

            Type(
                tT0ConsRef t0,
                tT1ConsRef t1,
                tT2ConsRef t2 = T2(),
                tT3ConsRef t3 = T3(),
                tT4ConsRef t4 = T4(),
                tT5ConsRef t5 = T5(),
                tT6ConsRef t6 = T6(),
                tT7ConsRef t7 = T7(),
                tT8ConsRef t8 = T8(),
                tT9ConsRef t9 = T9()
                ) :
            tCons0(t0, tCons1(t1, tCons2(t2, tCons3(t3, tCons4(t4, tCons5(t5,tCons6(t6,tCons7(t7,tCons8(t8,tCons9(t9))))))))))
            {
            }

            template<typename HeadT, typename TailT>
            Type(const ::Wiz::Tuple::Cons::Type<HeadT, TailT>& Other) : tCons0(Other.m_Head, Other.m_Tail)
            {
            }

            template<typename FirstT, typename LastT>
            tThis& operator=(const ::Wiz::Pair::Type<FirstT, LastT>& Other)
            {
                this->m_Head = Other.m_First;
                this->m_Tail.m_Head = Other.m_Last;
                return *this;
            }

            template<typename HeadT, typename TailT>
            tThis& operator=(const ::Wiz::Tuple::Cons::Type<HeadT, TailT>& Other)
            {
                this->m_Head = Other.m_Head;
                this->m_Tail = Other.m_Tail;

                return *this;
            }

            template <::Wiz::Int::Type N>
            typename ::Wiz::Tuple::Element::Ref<N, tSuper>::tReturn
            operator[](::Wiz::Tuple::Index::Type<N>)
            {
                return ::Wiz::Tuple::Get<N>(*this);
            }

            template <::Wiz::Int::Type N>
            typename ::Wiz::Tuple::Element::RefConst<N, tSuper>::tReturn
            operator[](::Wiz::Tuple::Index::Type<N>) const
            {
                return ::Wiz::Tuple::Get<N>(*this);
            }
        }; /// end of class Type
        ///////////////////////////////////////////////////////////////////////
    } /// end of namespace Tuple
} /// end of namespace Wiz

#endif /*__WIZ_DATATYPE_TUPLE_HPP__SHANHAOBO_19800429__*/
